package com.jbwz.web.security.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jbwz.web.common.base.BaseEntity;
import com.jbwz.web.common.base.BaseServiceImpl;
import com.jbwz.web.common.exception.BusinessException;
import com.jbwz.web.common.res.ResponseCodeBase;
import com.jbwz.web.common.session.SessionUser;
import com.jbwz.web.common.util.BeanUtilCommon;
import com.jbwz.web.security.entity.Resource;
import com.jbwz.web.security.entity.vo.ResourceVO;
import com.jbwz.web.security.enums.AdminFlagEnum;
import com.jbwz.web.security.enums.ResourceTypeEnum;
import com.jbwz.web.security.mapper.ResourceMapper;
import com.jbwz.web.security.service.ResourceService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 资源 服务实现类
 *
 * @author yyh
 * @since 2021-08-23 22:44:43
 */
@Service
public class ResourceServiceImpl extends BaseServiceImpl<ResourceMapper, Resource>
    implements ResourceService {

  @Override
  public List<ResourceVO> listByPid(Long pid) {
    QueryWrapper<Resource> wrapper = Wrappers.<Resource>query().eq("parent_id", pid);
    return list(wrapper).stream().map(this::toVO).toList();
  }

  /**
   * 根据父菜单id查询子菜单包含孙菜单
   *
   * @param pid
   * @return
   */
  @Override
  public List<ResourceVO> listByPidWithChildren(Long pid) {
    QueryWrapper<Resource> wrapper = Wrappers.<Resource>query().eq("parent_id", pid);
    List<Resource> resources = list(wrapper);
    Set<Long> idlist = resources.stream().map(BaseEntity::getId).collect(Collectors.toSet());
    QueryWrapper<Resource> childrenQW = Wrappers.<Resource>query().in("parent_id", idlist);
    Map<Long, List<ResourceVO>> collect =
        list(childrenQW).stream()
            .map(this::toVO)
            .collect(Collectors.groupingBy(ResourceVO::getParentId, Collectors.toList()));
    List<ResourceVO> objects =
        resources.stream()
            .map(
                e -> {
                  ResourceVO resourceVO = toVO(e);
                  resourceVO.setChildren(collect.get(e.getId()));
                  return resourceVO;
                })
            .toList();
    return objects;
  }

  /** 菜单最多3层，不用递归了,界面增删改时使用 */
  @Override
  public List<ResourceVO> listMenuTree() {
    QueryWrapper<Resource> wrapper =
        Wrappers.<Resource>query().eq("type", ResourceTypeEnum.MENU.getCode());
    List<Resource> list = this.list(wrapper);
    // 根菜单parentId默认为0，根据菜单父id分组
    Map<Long, List<ResourceVO>> resourceMap =
        list.stream().map(this::toVO).collect(Collectors.groupingBy(ResourceVO::getParentId));
    // 根菜单
    List<ResourceVO> rootMenuList = resourceMap.remove(0L);
    // 查找2级菜单设置3级菜单,就3级没必要用递归
    rootMenuList.forEach(
        resourceVOL1 -> {
          Long id1 = resourceVOL1.getId();
          if (resourceMap.containsKey(id1)) {
            List<ResourceVO> childrenL2 = resourceMap.remove(id1);
            resourceVOL1.setChildren(childrenL2);
            childrenL2.forEach(
                resourceVOL2 -> {
                  Long id2 = resourceVOL2.getId();
                  if (resourceMap.containsKey(id2)) {
                    List<ResourceVO> childrenL3 = resourceMap.remove(id2);
                    resourceVOL2.setChildren(childrenL3);
                  }
                });
          }
        });
    return rootMenuList;
  }

  @Override
  public void saveOrUpdateWithCheck(Resource e) {
    checkNameOrPkey(e);
    saveOrUpdate(e);
  }

  /**
   * 查询当前用户所授权的资源
   *
   * @param user 用户id
   */
  @Override
  public List<Resource> getCurrentUserResource(SessionUser user) {
    Integer adminFlag = user.getAdminFlag();
    if (AdminFlagEnum.SUPER_ADMIN.getCode().equals(adminFlag)) {
      // 如果是超级管理员有所有的权限
      Resource resource = new Resource();
      resource.setPath("/**");
      resource.setAuthKey("allauth");
      resource.setName("所有权限");
      List<Resource> list = this.list();
      list.add(resource);
      return list;
    } else {
      return baseMapper.getCurrentUserResource(user.getId(), false).stream()
          .filter(
              r -> {
                String path = r.getPath();
                return !(StringUtils.isNotBlank(path)
                    && (path.startsWith("/resource") || path.startsWith("/company")));
              })
          .toList();
    }
  }

  @Override
  public Set<String> getCurrentUserResourcePkey(SessionUser user) {
    List<Resource> list = getCurrentUserResource(user);
    Set<String> checkedList =
        list.stream()
            .map(Resource::getAuthKey)
            .filter(StringUtils::isNotBlank)
            .collect(Collectors.toSet());
    return checkedList;
  }

  private void checkNameOrPkey(Resource e) {
    QueryWrapper<Resource> wrapper =
        Wrappers.<Resource>query().eq("name", e.getName()).or().eq("auth_key", e.getAuthKey());
    List<Resource> list = list(wrapper);
    if (!CollectionUtils.isEmpty(list)) {
      if (Objects.nonNull(e.getId())) {
        Resource byId = getById(e.getId());
        if (Objects.nonNull(byId)
            && list.size() == 1
            && (byId.getName().equals(e.getName()) || byId.getAuthKey().equals(e.getAuthKey()))) {
          // 更新时可能名字不变,更新其它字段
          return;
        }
      }
      throw BusinessException.resMsg(ResponseCodeBase.dataExist.withMsg("菜单名或权限标识已存在"));
    }
  }

  public ResourceVO toVO(Resource o) {
    ResourceVO vo = BeanUtilCommon.copy(o, new ResourceVO());
    return vo;
  }
}
